using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Drawing;

namespace MapEditor
{
    #region class ZPathVisiblePoint
    public class PathVisiblePoint
    {
        public float fDistance = 0.0f;
        public ZPathPoint pVisiblePoint = null;
    }
    #endregion
 
    #region class ZPathPoint
    public class ZPathPoint
    {
        public Point pos = new Point();
        public ArrayList VisiblePoints = new ArrayList();
    }
    #endregion
 

    #region class ZPathManager
    public class ZPathManager
    {
        public ArrayList m_PathPoints = new ArrayList();
 
        #region ZPathPoint GetClosestItem(Point pos)

        public ZPathPoint GetClosestItem(Point pos)
        {
            ZPathPoint retVal = null;
 
            float fClosest = float.MaxValue;
 
            foreach(ZPathPoint p in m_PathPoints)
            {
                float f = GetDistance(pos, p.pos);//(p.pos-pos).Length();
                if(f<fClosest)
                {
                    fClosest = f;
                    retVal = p;
                }
            }
 
            return retVal;
        }
        #endregion

        public float GetDistance(Point StartPoint, Point EndPoint)
        //gets the distance beteen two points
        //here is where we set the increase for goodness of terrain
        //the worse the terrain is for moving, the higher the distance
        //for the moment, just return a standard 10
        {
            return 10F;
        }

        #region AddPoint
        public ZPathPoint AddPoint(Point pos)
        {
            ZPathPoint p = new ZPathPoint();
            p.pos = pos;
            m_PathPoints.Add(p);
            return p;
        }
       #endregion
 
        #region RemovePoint
        public void RemovePoint(Point pos)
        {
            ZPathPoint p = this.GetClosestItem(pos);
            if(p != null)
            {
                foreach(PathVisiblePoint vis in p.VisiblePoints)
                {
                    vis.pVisiblePoint.VisiblePoints.Remove(p);
                }
                m_PathPoints.Remove(p);
            }
        }
        #endregion
    }
    #endregion
 
    #region class ZPathFinderManager
    class ZPathFinderManager
    {
        private Hashtable m_VisitedList = new Hashtable();
 
        ZPathPoint m_pStartPath = null;
        ZPathPoint m_pEndPath = null;
 
        ArrayList m_path = new ArrayList();
        bool m_bHasPath = false;
 

        #region void ClearPath()
        public void ClearPath()
        {
            m_bHasPath = false;
            m_path.Clear();
            m_VisitedList.Clear();
        }
        #endregion
 
        #region ZPathPoint GetClosestNonVisitedItem(ZPathPoint pFrom)
        public ZPathPoint GetClosestNonVisitedItem(ZPathPoint pFrom)
        {
            //loop thru this items visible list and 
            //find the closest that hasnt been visited
            float fClosest = float.MaxValue;
            PathVisiblePoint pClosestVisiblePoint = null;
 
            foreach(PathVisiblePoint pVisiblePoint in pFrom.VisiblePoints)
            {
                //check if this point has been visited,
                if(m_VisitedList[(pVisiblePoint.pVisiblePoint.GetHashCode()<<16)
                                    | pVisiblePoint.GetHashCode()] == null)
                {
                    //Point vDist = this.m_pEndPath.pos - pVisiblePoint.pVisiblePoint.pos;
                    //the length between two points
                    //float fdist = vDist.Length();
                    float fdist = GetDistance(pFrom.pos, pVisiblePoint.pVisiblePoint.pos);
                    //check its distance
                    if(fdist<fClosest)
                    {
                        fClosest = fdist;
                        pClosestVisiblePoint = pVisiblePoint;
                    }
                }
            }
 
            //mark this point as visited
            if(pClosestVisiblePoint != null)
            {
                m_VisitedList[(pClosestVisiblePoint.pVisiblePoint.GetHashCode()<<16)
                    | pClosestVisiblePoint.GetHashCode()] = true;
 
                return pClosestVisiblePoint.pVisiblePoint;
            }
            else
            {
                return null;
            }
        }
        #endregion

        public float GetDistance(Point StartPoint, Point EndPoint)
        //gets the distance beteen two points
        //here is where we set the increase for goodness of terrain
        //the worse the terrain is for moving, the higher the distance
        //for the moment, just return a standard 10
        {
            return 10F;
        }

        #region bool FindPath()
        public bool FindPath()
        {
            ClearPath();
 
            if((m_pEndPath   == null) || 
               (m_pStartPath == null))
            {
                return false;
            }
            else if(m_pEndPath == m_pStartPath) //address compare
            {
                m_path.Add(m_pStartPath);
                m_path.Add(m_pEndPath);
                m_bHasPath = true;
                return true;
            }
 
            ZPathPoint pStartFrom = m_pStartPath;
 
            //set the start point in the member path
            m_path.Add(pStartFrom);
 
            while(m_pEndPath != pStartFrom)
            {
                //start A-Star path finding
                ZPathPoint pItem = GetClosestNonVisitedItem(pStartFrom);
 
                if(pItem != null)
                {
                    //add this to the path list
                    m_path.Add(pItem);
 
                    //start from here
                    pStartFrom = pItem;
                }
                else
                {
                    //there was no good path found
                    //remove the last item
                    if(m_path.Count > 0)
                        m_path.RemoveAt(m_path.Count-1);
 
                    if(m_path.Count > 0)
                    {
                        //pop back the path to the last position where 
                        //there are more nodes to search
                        pStartFrom = (ZPathPoint)m_path[m_path.Count-1];
                    }
                    else
                    {
                        //no possible path found
                        return false;
                    }
                }
            }
            m_bHasPath = true;
            return true;
        }
        #endregion
 
        #region void OptimizePath()
        public void OptimizePath()
        {
            if(m_path.Count > 2)
            {
                int nFoundAt=0;
 
                for(int i=0; i < m_path.Count -1 ;i++)
                {
                    ZPathPoint pPath = (ZPathPoint)m_path[i];
 
                    for(int j=i+1; j < m_path.Count ; j++ )
                    {
                        ZPathPoint pPath2 = (ZPathPoint)m_path[j];
 
                        foreach(PathVisiblePoint pVis in pPath2.VisiblePoints)
                        {
                            if(pVis.pVisiblePoint == pPath)
                            {
                                if(j > i + 1)
                                {
                                    nFoundAt = j;
                                }
                            }
                        }
                    }
 
                    if (nFoundAt != 0)
                    {
                        for (int k = nFoundAt - 1; k > i; --k)
                        {
                            m_path.RemoveAt(k);
                        }
                        nFoundAt = 0;
                    }
                }
            }
        }
        #endregion
    }
    #endregion
}
